#ifndef HTTP_H
#define HTTP_H
#include<vector>
#include<deque>
#include<string>
#include<cstdlib>
#include<functional>
#include<iostream>
#include<sstream>
#include"tcp.hpp"

using namespace std;

class Url
{
public:
  string scheme;
  string auth;
  string host;
  string path;
  vector<pair<string, string> > params;  
  int port;
  
  Url(const string& url);
  
  string get_query_str() const;
  
  string to_string() const;
  
  ostream& out_to(ostream &out) const;

  static int scheme_port(const string&sche);

  int default_port() const;
};


struct Proxy
{
  Url purl;

  Proxy(const string& str=string()): purl(str) {  }
  Proxy(const Url& url): purl(url) { }

  bool empty() const;

};

class HttpHeader
{
  vector<pair<string,string> > headers;

public:
  void clear();

  void merge(const HttpHeader &o);
  
  void add(const string& k, const string& v);

  void remove(const string&k);
  
  string get(const string& k)const;
  
  // >0 still in//0 finish //-1 not know //<-1 error
  int fetch_from(string& str);
  
  string to_string(const HttpHeader*hd=0) const;
  string to_contstr(const HttpHeader*hd=0) const;
  
  string to_dbgstring() const;
  
};

class HttpRequest
{
public:
  HttpHeader header;
  HttpHeader cont;
  typedef enum {Method_GET, Method_POST, Method_PUT, Method_DELETE}Method;
  Method method;
  Url url;

  HttpRequest(const Url& u, Method m = Method_GET);
  
  void add_header(const string& k, const string& v);

  void add_cont(const string&k, const string&v);
  
  string get_host()const;
  
  int get_port()const;
  
  string build_com(int full=false)const;
  
  string build_header(const HttpHeader* oh=0)const; 
};

class HttpRequestPost:public HttpRequest
{
public:
  HttpHeader cont;
  string content_type;

  HttpRequestPost(const Url& u);
  
  void add_cont(const string&k, const string&v);
  
  void add_cont(const string&ed);
  
  string build_cont(const HttpHeader* oh=0)const;
  
  string build_com(int full) const;

};

class HttpResponse
{
public:
  HttpHeader header;
  int ret;
  string statusline;
  string content;
  int contentlen;
  int ischunked;
  int lastchunked;
  int fstatus;

  int fetch_from(TcpClient& tcpclient, string &str, bool start=false);
  
  //>0 should again// 0 done//== -1 error//<-1 not know 
  int fetch_from(string &str, bool start=false);
  
  bool is_success();
  
  string to_string();
  
};
  
class HttpAgent
{
  Proxy proxy;
  TcpClient tcpclient;
  HttpHeader header;
  int timeout;
  
public:
  
  explicit HttpAgent(int to=20000);
  
  void set_proxy(const string& u=string());
  
  bool has_proxy()const;
  
  int request(HttpResponse& resp, const HttpRequest& req);
  
  int fetch(HttpResponse &resp, string& str, bool fstart=false);
  
};


#endif
